﻿<#
MIT License
Copyright (c) 2016 powershell-kitchen.com/ PS Cheff
http://www.powershell-kitchen.com/page/mit-license
Published on: http://powershellkitchen.com/post/generate-viewmodel
#>

  <#
  .SYNOPSIS
      Generates a model class to use with data-binding.
  .DESCRIPTION
      When working with MVVM programs and XAML it is common to create models that implements INotifyPropertyChanged.
      This script generates the modesl from a CSV file with the following columns: ClassName,FieldName,BaseType,IsCollection,Description


  .EXAMPLE
      .\Generate-ViewModel.ps1 ".\SampleModel.csv" ".\TestUWPApp\TestUWPApp\Generated" "powershellkitchen.sample"

  .PARAMETER filePath
      filepath of the CSV file defining the model

  .PARAMETER outputFolder
      folder where the generated files will be stored
        
  .PARAMETER namespace
      namespace of the generated classes

  #>

Param(
  [Parameter(Mandatory=$True, Position=1)]
   [string]$filePath,
	
   [Parameter(Mandatory=$True, Position=2)]
   [string]$outputFolder,

   [Parameter(Mandatory=$True, Position=3)]
   [string]$namespace
)

function Get-ClassSourceCode($className, $classFields, $namespace)
{
    [System.Text.StringBuilder] $sb = new-object "System.Text.StringBuilder"    
    [void]$sb.AppendLine("// <auto-generated />")
    [void]$sb.AppendLine()
    [void]$sb.AppendLine("using System;")
    [void]$sb.AppendLine("using System.ComponentModel;")
    [void]$sb.AppendLine("using System.Collections.ObjectModel;")
    [void]$sb.AppendLine()
    [void]$sb.AppendLine("namespace $namespace")
    [void]$sb.AppendLine("{")
    [void]$sb.AppendLine()
    [void]$sb.AppendLine("`tpublic partial class " + $className +" : INotifyPropertyChanged")
    [void]$sb.AppendLine("`t{")

    foreach($field in $classFields)
    {
        [void]$sb.AppendLine("`t`tprivate " + $field.DeclarationType + " " + $field.MemberName + ";")
    }
    [void]$sb.AppendLine()    

    foreach($field in $classFields)
    {
        [void]$sb.AppendLine("`t`t///<summary>")    
        [void]$sb.AppendLine("`t`t/// "+ $field.Description)    
        [void]$sb.AppendLine("`t`t///</summary>")    
        [void]$sb.AppendLine("`t`tpublic "+$field.DeclarationType+" " + $field.FieldName)
        [void]$sb.AppendLine("`t`t{")    
        [void]$sb.AppendLine("`t`t`tget")    
        [void]$sb.AppendLine("`t`t`t{")    
        [void]$sb.AppendLine("`t`t`t`treturn "+ $field.MemberName+";")    
        [void]$sb.AppendLine("`t`t`t}")
        [void]$sb.AppendLine("`t`t`tset")    
        [void]$sb.AppendLine("`t`t`t{")    
        [void]$sb.AppendLine("`t`t`t`tif (value != " + $field.MemberName + ")" )    
        [void]$sb.AppendLine("`t`t`t`t{")    
        [void]$sb.AppendLine("`t`t`t`t`t" + $field.MemberName + "=value;" )    
        [void]$sb.AppendLine("`t`t`t`t`tNotifyPropertyChanged(`"" + $field.FieldName + "`");" )    
        [void]$sb.AppendLine("`t`t`t`t}" )    
        [void]$sb.AppendLine("`t`t`t}")      
        [void]$sb.AppendLine("`t`t}")    
        [void]$sb.AppendLine()    
    }
    [void]$sb.AppendLine("`t`t///<summary>")    
    [void]$sb.AppendLine("`t`t/// INotifyPropertyChanged.PropertyChanged")    
    [void]$sb.AppendLine("`t`t/// Occurs when a property value changes")    
    [void]$sb.AppendLine("`t`t///</summary>")    
    [void]$sb.AppendLine("`t`tpublic event PropertyChangedEventHandler PropertyChanged;")    
    [void]$sb.AppendLine()    
    [void]$sb.AppendLine("`t`t///<summary>")    
    [void]$sb.AppendLine("`t`t/// Notifies of changes in a field")    
    [void]$sb.AppendLine("`t`t///</summary>")    
    [void]$sb.AppendLine("`t`tprivate void NotifyPropertyChanged(String propertyName)")    
    [void]$sb.AppendLine("`t`t{")    
    [void]$sb.AppendLine("`t`t`tif (PropertyChanged != null)")    
    [void]$sb.AppendLine("`t`t`t{")    
    [void]$sb.AppendLine("`t`t`t`tPropertyChanged(this, new PropertyChangedEventArgs(propertyName));")    
    [void]$sb.AppendLine("`t`t`t}")    
    [void]$sb.AppendLine("`t`t}")    
    [void]$sb.AppendLine()    

    [void]$sb.AppendLine("`t}")
    [void]$sb.AppendLine("}")
    return $sb.ToString()
}

$modelInfo = import-csv $filePath
$classes = @{}
foreach($modelRow in $modelInfo)
{
    $memberName = "_"+ $modelRow.FieldName.Substring(0,1).ToLower()+$modelRow.FieldName.Substring(1)
    Add-Member -InputObject $modelRow -MemberType NoteProperty -Name "MemberName" -Value $memberName

    if ($modelRow.IsCollection -eq 'Yes')
    {
        $declarationType = "ObservableCollection<"+$modelRow.BaseType+">"
    }
    else
    {
        $declarationType = $modelRow.BaseType
    }
    Add-Member -InputObject $modelRow -MemberType NoteProperty -Name "DeclarationType" -Value $declarationType

    $classFields = $classes[$modelRow.ClassName];
    if ($classFields -eq $null)
    {
        $classFields = @()
        $classes.Add($modelRow.ClassName, $classFields)
    }
    $classFields += $modelRow
    $classes[$modelRow.ClassName] = $classFields
}

foreach($className in $classes.Keys)
{
    $sourceCode = Get-ClassSourceCode $className $classes[$className] $namespace
    $filePath = "$outputFolder\g_$className.cs" 
    Set-Content -Path $filePath -Value $sourceCode
}

